// globals

var head;
var caret;

var comcaret;
var comhead;

var slashFlag=0;
var debug=0;

// mouse events
var foundNodeWithElement=null;
var offsetX, offsetY;



// Engine: Abstract Tree Core

function Node()
{
    this.children = new Array();
}

Node.prototype.getChildAtPosition = function(index)
{
    return this.children[index];
}

// newNode.insert(parent)
Node.prototype.append = function(parent)
{
    parent.children.push(this);
    // Record its parent when a node is inserted
    this.parent = parent;
}

// newNode.insertAtPosition(parent,position)
Node.prototype.insertAtPosition = function(parent,index)
{
    parent.children.splice(index,0,this);
    this.parent = parent;
}

// newNode.insertAfter(oldNode)
Node.prototype.insertAfter = function(node)
{
    // node.parent is valid because it is recorded when the old node is inserted
    var p = node.parent;
    var i = p.children.indexOf(node);
    this.insertAtPosition(p,i+1);
}

Node.prototype.insertBefore = function(node)
{
    var p = node.parent;
    var i = p.children.indexOf(node);
    this.insertAtPosition(p,i);
}

Node.prototype.previous = function () {
	var p = this.parent;
    var i = p.children.indexOf(this);
 
    if(i>=1) {
		return p.children[i-1];   
    }
    else {
	    return null;
    }
}

Node.prototype.next = function () {
    var p = this.parent;
    var i = p.children.indexOf(this);
    var len=p.children.length;
    
    if(i<len-1) {
	 	return p.children[i+1];   
    }
    else {
	    return null;
    }
}

Node.prototype.remove = function () {
	var p = this.parent;
    var i = p.children.indexOf(this);
    
    this.node.remove();
    p.children.splice(i,1);
}

Node.prototype.childrenWithOperator = function (name) {
	var l = this.children.length;
	
	if(l==0) {
		return null;
	}
	
	else {
		for(var i=0;i<l;i++) {
			if(this.children[i].operator==name)
			{
				return this.children[i];
			}
		}
		return null;
	}
}


// Show Caret

function heightCaret(node) {  // this is temporary. Not a very good way of estimation
	switch (node.level) {
		case 1:
		return 24;
		break;
		case 2:
		return 21;
		break;
		case 3:
		return 17;
		break;
		case 4:
		return 13;
		break;
		case 5:
		return 12;
		break;
		default:  // all lever above 5 returns 11
		return 12;
		break;
	}
}

function textSizeFromLevel(level) {
	switch (level) {
		case 1:
		return 24;
		break;
		case 2:
		return 21;
		break;
		case 3:
		return 17;
		break;
		case 4:
		return 13;
		break;
		case 5:
		return 12;
		break;
		default:  // all lever above 5 returns 11
		return 12;
		break;
	}
}

function showCaret() {
	
	var leftElement, rightElement, length;
	
//	alert(caret.attr("class")+caret.attr("flag"));
	
	$('#caret').css('left',caret.node.offset().left+caret.width);
	$('#caret').css('top',caret.node.offset().top);
	if(caret.node.height()!=0) {
		$('#caret').css('height',caret.node.height());	
	}
	else {
		$('#caret').css('height',heightCaret(caret));
		$('#caret').css('top',caret.node.offset().top-heightCaret(caret));
	}
	
	leftElement=caret.parent.children[0];
	length=caret.parent.children.length;
	rightElement=caret.parent.children[length-1];
	
	
	$('#left').css('left',leftElement.node.offset().left);
	$('#left').css('top',leftElement.node.offset().top+leftElement.node.height()-$('#left').height());

	$('#right').css('left',rightElement.node.offset().left+rightElement.width);
	$('#right').css('top',rightElement.node.offset().top+rightElement.node.height()-$('#right').height());
	
	if(rightElement.node.offset().left+rightElement.width==leftElement.node.offset().left) 
	{
		$('#right').hide();
		$('#left').hide();
	}
	else if ($('#right').is(":hidden"))
	{		
		$('#right').show();
		$('#left').show();
	}
	
}

// Engine Controls

function skipOperatorsDown(node) { 

	var temp;
	var flag=0;
	var length;
	
	
	if(node.type!="operator"||node.children.length<=0)
	{
		return node.parent;
	}
	
	temp=node;
	
	while(!flag)  
	{	
		node=temp.children;
		length=node.length;
		for(var i=0;i<length;i++) {
			
			if(node[i].type!="operator")
			{	
				temp=node[i];
				flag=1;
				break;
			}
			else if(node[i].flag=="subOperator"&&node[i].children.length>0) {
					temp=node[i];
					break;		
			}
		}
		
	}
	
	return temp;

}

function skipOperatorsUp(node) {
	
	node=node.parent;
	
	while(node.type=="operator")  //skip operators, refined
	{	
		if(node.flag=="superOperator") {
				return node.previous();
		}
		else if(node.parent!=null){
				node=node.parent;
		}
		else {
			return node;
		}
	}
	
	return node;

}

function moveLeft(node) {  // it never starts with an operator node.
	
	if(node.previous()!=null) 
	{
		return node.previous();	
	}
	else if(node.parent!=null) 
	{	
		if(node.parent.level==0) 
		{
			return node;
		}
		else {
			return skipOperatorsUp(node);
		}
	}
	else 
	{
		return node;
	}
}

function moveRight(node) { // it never starts with an operator node. replace class by type.

	if(node.next()!=null) {
		if(node.next().type!="operator") 
		{
			return node.next();
		}	
		else {
			node=node.next();
			return skipOperatorsDown(node);
		}
	}
	else if(node.parent!=null)
	{
		if(node.parent.level==0) {
			return node;
		}
		else if(node.parent.flag=="superOperator") 
		{
			return node.parent;
		}
		else {
			node=node.parent;
			return moveRight(node);
		}
	}
	
}

function deletion(node) {

	if(node.previous()!=null) {
		node=node.previous();
		node.next().remove();
		return node;
	}
	else if(node.parent!=null) 
	{	
		if(node.parent.level=="0") {
			return node;	
		}
		else {
			node=skipOperatorsUp(node);
			node.next().remove();
			return node;	
		}
	}
	else 
	{
		return node;
	}
}

// Prepare Engine

function prepareEngine() {
	
	var newNode;
	
	head=new Node();
	
	newNode=$('<div></div>').appendTo($('#math'));
	
	head.level=0;
	head.width=0;
	head.parent=null; // End of Tree Top.
	head.node=newNode;
	
	caret=contentNodeAppend(head,0);

	updateTree(head,indexOfCaret(caret));
	
} 

// Engine: Typesetting Peripherals

function sumWidthChildren(node) {
	var sumWidth=0;
	var temp;
	var length;
	var children;
	
	children=node.children;
	length=children.length;

	if(length>0) 
	{
		for(var i=0;i<length;i++) 
		{
			sumWidth+=children[i].width;
		}
		return sumWidth;
	}
	else
	{
		return 0;
	}
}

function maxWidthChildren(node) { //used for Conglammeration
	var maxWidth=0;
	var temp;
	var length;
	var children;
	
	children=node.children;
	length=children.length;

	if(length>0) 
	{
		for(var i=0;i<length;i++) 
		{
			maxWidth=Math.max(children[i].width,maxWidth);
		}
		return maxWidth;
	}
	else
	{
		return 0;
	}
}

function ascentChildren(node) {
	var tempAscent=0;
	var maxAscent=0;
	var children;
	var length;
	
	children=node.children;
	length=children.length;
	
	if(length>0) {
		for(var i=0;i<length;i++) 
		{
			tempAscent=children[i].ascent;
			maxAscent=Math.max(maxAscent,tempAscent);
		}
		return maxAscent;
	}
	else {
		return 0;
	}
}

function descentChildren(node) {
	var tempDescent=0;
	var maxDescent=0;
	var children;
	var length;
	
	children=node.children;
	length=children.length;
	
	if(length>0) {
		for(var i=0;i<length;i++) 
		{
			tempDescent=children[i].descent;
			maxDescent=Math.max(maxDescent,tempDescent);
		}
		return maxDescent;
	}
	else {
		return 0;
	}
}

// Engine: Typesetting Core

function offSetForGeneral(node) {
	var operatorNode;
	var upOffset=0;
	var downOffset=0;
	var selfHeight;
	var selfWidth; // for left alignment in fraction
	var height;
	
	var upOffsetTop=0;
	var downOffsetTop=0;
	var upOffsetBottom=0;
	var downOffsetBottom=0;
	
	var heightTop=0;
	var heightBottom=0;
	
	var widthThis=0;
	
	var length;
	
	node.upOffSet=0;
	node.downOffSet=0;
	
	operatorNode=node.children;
	selfHeight=node.height;
	selfWidth=node.width;
	
	length=operatorNode.length;
	
	if(length<=0) {
		return 0;
	}
	
	else {  
		for(var i=0;i<length;i++){
			element=operatorNode[i];
			if(element.operator=="up"){
				widthThis=element.width;
				heightTop=element.height;
				upOffsetTop=upOffSetChildren(element);
				downOffsetTop=downOffSetChildren(element);
				element.node.css('bottom',0);  // no need to compensate for Downoffset
				element.node.css('left',0); // no need to compensate for Left Alignment
				node.upOffSet=upOffsetTop+heightTop-selfHeight;
				node.downOffSet=downOffsetTop;
				break;
			}
		}

	}
}

// Engine: Update and Display Core, Association Method.

function indexOfCaret(node) {
	var element=node;
	
	if(element.parent==null) {
		return 0;
	}
	else {
		while(element.parent!=head){
			element=element.parent;
		}
	}

	return head.children.indexOf(element);
	
}

function updateTree(node,startIndex) {

//
	var children;
	var prevCaret;  //previous caret
	var element;
	
	var oldWidth=0;
	var oldAscent=0;
	var oldDescent=0;
	
	var thisNode;
	
	var length;
	
// you can not get any information from your parents. should be able to bypass auxoperator

	children=node.children;
	
	if(children.length<=0){  // if no child
		return 0;
	}
	
	length=children.length;
	
	prevCaret=node.getChildAtPosition(startIndex-1);

	for(var i=startIndex;i<length;i++) {
		element=children[i];    
	
		if(element.children.length>0)   //recursion
		{
			updateTree(element,0);
		}  
		
		if(element.operator=="conglam")   //  ^ and _
		{   offSetForConglam(element);
		}
		else if(element.operator=="fraction") {	
			offSetForFraction(element);
		}
		else if(element.operator=="overline") {
			offSetForOverline(element);
		}
		else if(element.operator=="underline") {	
			offSetForUnderline(element);
		}
		else if(element.operator=="parenthesis") {	
			offSetForParenthesis(element);
		}
		else if(element.operator=="matrix") {	
			offSetForMatrix(element);
		}
		else if(element.operator=="column") {
//			element.width=sumWidthChildren(element);	
			offSetForColumn(element);
		}
		else if(element.flag=="superOperator"){
			offSetForGeneral(element);
		}
		// report width for non-auxOperator stuff to parents. 
		if(element.flag!="auxOperator") {	
		
// later change all flags into inherited Node. change the Node notation into Math, Operator, Content,xx
		
			if(element.flag!="subOperator") {
				if(element.type=="starter") {
					element.left=0;
					element.bottom=0;
					element.node.css('left',0);
					element.node.css('bottom',0);	
					// move the starter indicator here.
					if(element.parent.children.length==1) {
							element.width=element.oldWidth;
							element.node.attr('type','blank');
							element.node.css('width',element.width);	
							element.node.css('height',element.ascent);	
					}
					// check the first indicator from outside.
					else {
							element.node.attr('type','filled');
							element.width=0;
					}
				}
				else {
					thisLeft=prevCaret.left+prevCaret.width;
					thisBottom=prevCaret.bottom;
					element.left=thisLeft;
					element.bottom=thisBottom;
					element.node.css('left',thisLeft);
					element.node.css('bottom',thisBottom);		
				}
			}
			oldWidth+=element.width;
			element.parent.width=oldWidth;	
		}
	prevCaret=element;
	}
	
}

// Engine Events


function operatorType(keyCode) {
	if(keyCode==94) {
		return "up";
	}
	else if(keyCode==95) {
		return "down";
	}
}


function insertOperator(keyCode) {  // ^ and _ are now macros
	
	if (keyCode==92) // "\"
	{  
		prepareCommand();
	}
	
	else if(keyCode==32) { // "spacebar"

		endCommand();
	}
}

function nextLevel(level) {
	if(level<5) 
	{
		return level+1;
	}
	else 
	{
		return level;
	}
}

function insertElement(keyCode,message) {
	var level;
	var newNode;
	var text,textSize,textFont;
	var metric;
	
	var inp;
	
	// this is to fix the "-" in math mode;
	
	if(keyCode==45) {
		keyCode=8722;
	}
	
	
	level=caret.level; // accessing node prototype's level property 

	
	text=String.fromCharCode(keyCode);
	textSize=textSizeFromLevel(level);
	
	newNode=new Node();
	
	newNode.insertAfter(caret);
	
	newNode.node=$('<span>'+text+'</span>').insertAfter(caret.node);
	
	newNode.level=level;
	
	newNode.node.attr('level',level);

	if(message=="greek"){
		newNode.node.css('font-family',"stixgeneralitalic");
	}  
	else if(message=="math"){
		newNode.node.css('font-family',"stixgeneralregular");
	}
	
	inp=String.fromCharCode(keyCode);
	
	if(!(/[a-zA-Z0-9]/.test(inp)))
	{
		newNode.node.attr('font',"symbol");
	}
	textFont=newNode.node.css('font-family');  // need to make it dynamic
 	
 	result=textMetrics(textFont,text,textSize);
 	
	newNode.width=result.width; //report its own width.
	newNode.height=result.height; //report its own height.
	newNode.descent=result.descent; // report descender below baseline;
	newNode.ascent=result.ascent; // report ascender above baseline;
	
//	alert(result.height);
// measurement is different for different browers.
	$("#up").css("bottom",result.ascent-25);
	$("#baseline").css("bottom",-25);
	$("#down").css("bottom",-result.descent-25);
//	
	caret=newNode;
	
	updateTree(head,indexOfCaret(caret));
	showCaret();
} 

function keypress(e) {
	if(e.ctrlKey || e.metaKey)
    {
        return; // if ctr or command is pressed, do something else.
    }
    var keyCode = e.which;


//	alert(keyCode);
	
	if(!slashFlag) {
		if(keyCode==92||keyCode==32) { // if space bar or \:
	    	insertOperator(keyCode);
		}
		else if(keyCode==94||keyCode==95) {  // later, move to the Macro settings
			executeMacros(keyCode);
		}
		else if(keyCode==8||keyCode==37||keyCode==39||keyCode==38||keyCode==13) {
			;// deletion, up, down ,left and right.
		}
		else {
			insertElement(keyCode,"char"); 
		}
	}
	
	else if(slashFlag) {
		if(keyCode==32) { // if operator ^, _ \ and spacebar
	    	insertOperator(keyCode);
			showCaretCommand();
			;
		}
		else if(keyCode==8||keyCode==37||keyCode==39||keyCode==40||keyCode==38||keyCode==13) { //bypassing keydown events
			;// deletion, up, down ,left and right.
		}
		else {
			insertElementCommand(keyCode);
			showCaretCommand();
			;
		}
	}

}

// left, right and deletion
function keydown(e) {  //taking care of arrow keys
	var keyCode=e.which;
	var temp;
	
	if(!slashFlag) {
		if(keyCode==8){ //delete
			caret=deletion(caret);
			updateTree(head,indexOfCaret(caret));
			;
		}
	
		else if(keyCode==40){ //down
//			caret=moveDown(caret);
			;
		}
		else if(keyCode==38){ //up
//			caret=moveUp(caret);
			;
		}
		else if(keyCode==37){ //left
			caret=moveLeft(caret);
		}
		else if(keyCode==39){ //right   // Making the finding right element a nested operation
			caret=moveRight(caret);
		}
		else {
			return 0;
		}
		showCaret();
	}
	else if(slashFlag) {
		if(keyCode==8){ //delete
			comcaret=deletion(comcaret);
			updateTree(comhead,0);
		}

		else if(keyCode==37){ //left
			comcaret=moveLeft(comcaret);
		}
		else if(keyCode==39){ //right   // Making the finding right element a nested operation
			comcaret=moveRight(comcaret);
		}
		else {
			return 0;
		}
		showCaretCommand();
		;
	}

} 

// Execute MACROs

function executeMacros(code) {
	if(code==94) {
		executeCommand('superscript');
	}
	else if(code==95) {
		executeCommand('subscript');
	}
}

// Engine Commands

function prepareCommand(){
	
	var newNode;
	
	$('#command').css('left',caret.node.offset().left+caret.width);
	$('#symbol').css('left',caret.node.offset().left+caret.width-20);

	if(caret.node.height()!=0) {
		$('#command').css('top',caret.node.offset().top+caret.height);
		$('#symbol').css('top',caret.node.offset().top+caret.height);
	}
	else {
		$('#command').css('top',caret.node.offset().top);
		$('#symbol').css('top',caret.node.offset().top);
	}

	
	$('#command').show();
	$('#symbol').show();
	
	slashFlag=1;
	
	newNode=new Node();
	newNode.node=$('<div></div>').appendTo($('#command'));
	comhead=newNode;

	newNode=new Node();
	newNode.node=$('<span></span>').appendTo(comhead.node);
	comcaret=newNode;
	
	comcaret.append(comhead);  // establish the parent relation
	
	comhead.level=0;
	comhead.width=0;
	
	comcaret.level=2;
	comcaret.left=0;
	comcaret.bottom=0;
	comcaret.node.css('left',0);
	comcaret.node.css('bottom',0);
	comcaret.width=0;
	comcaret.height=18;
	comcaret.type="starter";
	
	$('#comcaret').show();
	showCaretCommand();
}

function fetchCommand(node) {

	var children=node.children;
	var command='';
	var length=children.length;
	
	if(length<=0) {
		return 0;
	}
	
	else {
		for(var i=0;i<length;i++) {
			command+=children[i].node.text();
		}
	}
	
	return command;
}

function executeCommand(string) {
	var fn=window[string];
	
	fn(caret);  //execute command
	updateTree(head,indexOfCaret(caret));
	showCaret();
}

function endCommand() {
	var command;
	
	command=fetchCommand(comhead);
	
	if(command=='[') {
		command="rectParenthesis";
	}
	
	else if(command=='{') {
		command="curlyParenthesis";
	}
	
	else if(command=='(') {
		command="regularParenthesis";
	}
	
	$('#command').empty();
	slashFlag=0;
	$('#command').hide();
	$('#symbol').hide();
	$('#comcaret').hide();
	
	executeCommand(command);
	
	
}

function insertElementCommand(keyCode){
	
	var level;
	var newNode;
	
		
	level=comcaret.level; // accessing node prototype's level property 
	newNode=new Node();
	
	newNode.insertAfter(comcaret);
	
	newNode.node=$('<span>'+String.fromCharCode(keyCode)+'</span>').insertAfter(comcaret.node);
	
	newNode.level=level;
	newNode.node.attr('level',level);
	
	newNode.width=newNode.node.width(); //report its own width.
	newNode.height=newNode.node.height(); //report its own height.
	
	
	comcaret=newNode;
	
	updateTree(comhead,0);
	showCaretCommand();
}

function showCaretCommand() {

	$('#comcaret').css('left',comcaret.node.offset().left+comcaret.width);
	$('#comcaret').css('top',comcaret.node.offset().top);
	if(comcaret.node.height()!=0) {
		$('#comcaret').css('height',comcaret.height);	
	}
	else {
		$('#comcaret').css('height',heightCaret(comcaret));
		$('#comcaret').css('top',comcaret.node.offset().top-heightCaret(comcaret));
	}	
}

// Mouse Function

function findNodeWithPosition(node){  //how to terminate 
	var children;
	var element;
	
	var length;
	
	var thisNode;
	
	
// you can not get any information from your parents.

	children=node.children;
	
	length=children.length;
	
	if(length<=0){  // if no child
		return 0;
	}

	for(var i=0;i<length;i++) {
		element=children[i];    
	
		if(element.children.length>0)   //recursion
		{
			findNodeWithPosition(element);
		}  
		

		if(isInRange(element)) {
			caret=element;
		}

	}
	
}

function isInRange(element) {
	
	etop=element.node.offset().top;
	eleft=element.node.offset().left;
	width=element.node.width();
	height=element.node.height();
	
	if((offsetX>=eleft&&offsetX<=eleft+width)&&(offsetY<=etop+height&&offsetY>=etop)) {
		return true;
	}
	
	return false;
	
}

function mouseDown(e) {
	
	offsetX=e.pageX;
	offsetY=e.pageY;
	
	findNodeWithPosition(head);
	
	showCaret();
}

// Engine Insersion Facilities

function superOperatorInsert(parent,name) { // insert
		var level;
		var newNode;
		
		level=parent.level;
		
		newNode=new Node();
		newNode.node=$('<span></span>').insertAfter(parent.node);
		newNode.insertAfter(parent);
		newNode.level=level;
		newNode.type="operator";
		newNode.flag="superOperator";
		newNode.width=0;
		newNode.operator=name;
		newNode.ascent=0;
		newNode.descent=0;
		newNode.height=0;
		
		return newNode;
}

function superOperatorAppend(parent,name) { // append

		var level;
		var newNode;
		
		level=parent.level;
		
		newNode=new Node();
		newNode.node=$('<span></span>').appendTo(parent.node);
		newNode.append(parent);
		newNode.level=level;
		newNode.type="operator";
		newNode.flag="superOperator";
		newNode.width=0;
		newNode.operator=name;
		newNode.ascent=0;
		newNode.descent=0;
		newNode.height=0;
		
		return newNode;
}

function subOperatorAppend(parent,name) { // append

		var level;
		var newNode;
		
		level=parent.level;
		
		newNode=new Node();
		newNode.node=$('<span></span>').appendTo(parent.node);
		newNode.append(parent);
		newNode.level=level;
		newNode.type="operator";
		newNode.flag="subOperator";
		newNode.width=0;
		newNode.operator=name;
		newNode.height=0;
		newNode.ascent=0;
		newNode.descent=0;
		
		return newNode;
}

function auxOperatorAppend(parent,name) { // append

		var level;
		var newNode;
		
		level=parent.level;
		
		newNode=new Node();
		newNode.node=$('<span></span>').appendTo(parent.node);
		newNode.append(parent);
		newNode.level=level;
		newNode.type="operator";
		newNode.flag="auxOperator";
		newNode.width=0;
		newNode.operator=name;
		newNode.height=0;
		newNode.ascent=0;
		newNode.descent=0;
		newNode.node.attr('aux',name);
		
		return newNode;
}

function subOperatorInsertAfter(sibling,name) {

		var level;
		var newNode;
		
		level=sibling.level;
		
		newNode=new Node();
		newNode.node=$('<span></span>').insertAfter(sibling.node);
		newNode.insertAfter(sibling);
		newNode.level=level;
		newNode.type="operator";
		newNode.flag="subOperator";
		newNode.width=0;
		newNode.operator=name;
		newNode.height=0;
		newNode.ascent=0;
		newNode.descent=0;
		
		return newNode;
	
	
}

function subOperatorInsertBefore(sibling,name) {

		var level;
		var newNode;
		
		level=sibling.level;
		
		newNode=new Node();
		newNode.node=$('<span></span>').insertBefore(sibling.node);
		newNode.insertBefore(sibling);
		newNode.level=level;
		newNode.type="operator";
		newNode.flag="subOperator";
		newNode.width=0;
		newNode.operator=name;
		newNode.height=0;
		newNode.ascent=0;
		newNode.descent=0;
		
		return newNode;
	
	
}

function auxOperatorInsert(parent,name) { // append
		var level;
		var newNode;
		
		level=parent.level;
		
		newNode=new Node();
		newNode.node=$('<span></span>').appendTo(parent.node);
		newNode.append(parent);
		newNode.level=level;
		newNode.type="operator";
		newNode.flag="auxOperator";
		newNode.width=0;
		newNode.operator=name;
		newNode.height=0;
		newNode.node.attr('aux',name);
		newNode.ascent=0;
		newNode.descent=0;
		
		return newNode;
}


function contentNodeAppend(parent,flag) { //append
		var level;
		var newNode;
		var result;
		
		level=parent.level;
		
		newNode=new Node();
		newNode.node=$('<span></span>').appendTo(parent.node);
		newNode.append(parent);
		if(flag==0) {
			newNode.level=nextLevel(level);
		}
		else {
			newNode.level=level;
		}
		
		result=textMetrics(newNode.node.css('font-family'),"a",textSizeFromLevel(level));
		newNode.oldHeight=result.height;
		newNode.oldWidth=result.width/2;
		newNode.type="starter";
		newNode.node.attr('type','blank');
		
		newNode.height=0;
		newNode.width=0;
		newNode.ascent=result.ascent;
		newNode.descent=result.descent;  // for use of getMetrics
		
		return newNode;
}

$(document).keypress(keypress);
$(document).keydown(keydown);
$(document).ready(prepareEngine);
$(document).mousedown(mouseDown);